<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Spring Batch 核心架构解析 | 技术小馆</title>
    <link rel="stylesheet" href="https://cdn.staticfile.org/tailwindcss/2.2.19/tailwind.min.css">
    <link rel="stylesheet" href="https://cdn.staticfile.org/font-awesome/6.4.0/css/all.min.css">
    <link href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;500;600;700&family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/mermaid@latest/dist/mermaid.min.js"></script>
    <style>
        body {
            font-family: 'Noto Sans SC', 'Noto Serif SC', Tahoma, Arial, Roboto, "Droid Sans", "Helvetica Neue", "Droid Sans Fallback", "Heiti SC", "Hiragino Sans GB", Simsun, sans-serif;
            color: #333;
            line-height: 1.6;
        }
        .gradient-bg {
            background: linear-gradient(135deg, #6e8efb 0%, #a777e3 100%);
        }
        .card-hover {
            transition: all 0.3s ease;
        }
        .card-hover:hover {
            transform: translateY(-5px);
            box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
        }
        .code-block {
            background-color: #2d2d2d;
            color: #f8f8f2;
            border-radius: 0.5rem;
            padding: 1rem;
            font-family: 'Courier New', Courier, monospace;
            position: relative;
        }
        .code-block .copy-btn {
            position: absolute;
            top: 0.5rem;
            right: 0.5rem;
            color: #ccc;
            cursor: pointer;
            transition: color 0.2s;
        }
        .code-block .copy-btn:hover {
            color: white;
        }
        .section-divider {
            height: 1px;
            background: linear-gradient(90deg, rgba(0,0,0,0) 0%, rgba(167,119,227,0.5) 50%, rgba(0,0,0,0) 100%);
            margin: 3rem 0;
        }
        .first-letter:first-letter {
            float: left;
            font-size: 3.5em;
            line-height: 0.8;
            margin: 0.1em 0.2em 0 0;
            color: #6e8efb;
            font-weight: bold;
            font-family: 'Noto Serif SC', serif;
        }
    </style>
</head>
<body class="bg-gray-50">
    <!-- Hero Section -->
    <div class="gradient-bg text-white py-20 px-4 sm:px-6 lg:px-8">
        <div class="max-w-4xl mx-auto text-center">
            <h1 class="text-4xl md:text-5xl font-bold mb-6">Spring Batch 核心架构解析</h1>
            <p class="text-xl md:text-2xl opacity-90 mb-8">探索批量处理框架的强大功能与优雅实现</p>
            <div class="flex justify-center space-x-4">
                <a href="#core-structure" class="px-6 py-3 bg-white text-purple-700 font-semibold rounded-lg hover:bg-opacity-90 transition duration-200">
                    <i class="fas fa-layer-group mr-2"></i>核心架构
                </a>
                <a href="#workflow" class="px-6 py-3 bg-opacity-20 bg-white text-white font-semibold rounded-lg hover:bg-opacity-30 transition duration-200">
                    <i class="fas fa-project-diagram mr-2"></i>工作流程
                </a>
            </div>
        </div>
    </div>

    <!-- Main Content -->
    <div class="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
        <!-- Introduction -->
        <div class="mb-16">
            <p class="text-lg text-gray-700 first-letter">
                Spring Batch 是一个用于批量处理的框架，它提供了非常强大和灵活的功能，如事务管理、作业执行、处理数据的分段等。我们将逐步分析其核心组件和工作流程，具体包括 Job、Step 的执行流程、ItemReader、ItemProcessor、ItemWriter 等的实现。
            </p>
        </div>

        <!-- 1. Spring Batch 核心结构 -->
        <section id="core-structure" class="mb-16">
            <div class="flex items-center mb-8">
                <div class="bg-purple-600 text-white rounded-full w-10 h-10 flex items-center justify-center mr-4">
                    <span class="text-xl font-bold">1</span>
                </div>
                <h2 class="text-3xl font-bold text-gray-800">Spring Batch 核心结构</h2>
            </div>
            
            <p class="text-gray-700 mb-6">
                Spring Batch 的核心是基于 <code class="bg-gray-100 px-2 py-1 rounded">Job</code> 和 <code class="bg-gray-100 px-2 py-1 rounded">Step</code> 构建的。一个 <code class="bg-gray-100 px-2 py-1 rounded">Job</code> 由多个 <code class="bg-gray-100 px-2 py-1 rounded">Step</code> 组成，每个 <code class="bg-gray-100 px-2 py-1 rounded">Step</code> 都代表了批处理中的一个阶段。每个 <code class="bg-gray-100 px-2 py-1 rounded">Step</code> 内部包括了数据的读取、处理和写入。Spring Batch 通过这些组件完成批量任务的处理。
            </p>
            
            <h3 class="text-xl font-semibold text-gray-800 mt-8 mb-4 flex items-center">
                <i class="fas fa-code text-purple-600 mr-2"></i> Job 和 Step 的定义：
            </h3>
            
            <div class="grid md:grid-cols-2 gap-6 mb-8">
                <div class="code-block">
                    <div class="copy-btn" onclick="copyCode(this)"><i class="far fa-copy"></i></div>
                    <pre><code>public interface Job {
    String getName();
    JobExecution run(JobParameters jobParameters) 
        throws JobExecutionException;
}</code></pre>
                </div>
                <div class="code-block">
                    <div class="copy-btn" onclick="copyCode(this)"><i class="far fa-copy"></i></div>
                    <pre><code>public interface Step {
    String getName();
    ExitStatus execute(StepExecution stepExecution) 
        throws StepExecutionException;
}</code></pre>
                </div>
            </div>
            
            <div class="bg-blue-50 border-l-4 border-blue-500 p-4 mb-8">
                <div class="flex">
                    <div class="flex-shrink-0 text-blue-500">
                        <i class="fas fa-info-circle"></i>
                    </div>
                    <div class="ml-3">
                        <p class="text-blue-700">
                            <code class="bg-blue-100 px-1 py-0.5 rounded">Job</code> 是整个批处理作业的入口，它可以包含多个 <code class="bg-blue-100 px-1 py-0.5 rounded">Step</code>，每个 <code class="bg-blue-100 px-1 py-0.5 rounded">Step</code> 负责完成某一部分工作。<br>
                            <code class="bg-blue-100 px-1 py-0.5 rounded">Step</code> 是 <code class="bg-blue-100 px-1 py-0.5 rounded">Job</code> 中的具体任务，负责数据的读取、处理和写入。
                        </p>
                    </div>
                </div>
            </div>
            
            <!-- Mermaid Diagram -->
            <div class="bg-white rounded-xl shadow-md p-6 mb-8">
                <h3 class="text-xl font-semibold text-gray-800 mb-4 flex items-center">
                    <i class="fas fa-project-diagram text-purple-600 mr-2"></i> Job 与 Step 关系图
                </h3>
                <div class="mermaid">
                    graph TD
                        A[Job] --> B[Step 1]
                        A --> C[Step 2]
                        A --> D[Step 3]
                        B --> E[ItemReader]
                        B --> F[ItemProcessor]
                        B --> G[ItemWriter]
                </div>
            </div>
        </section>

        <div class="section-divider"></div>

        <!-- 2. JobLauncher 的工作流程 -->
        <section id="workflow" class="mb-16">
            <div class="flex items-center mb-8">
                <div class="bg-purple-600 text-white rounded-full w-10 h-10 flex items-center justify-center mr-4">
                    <span class="text-xl font-bold">2</span>
                </div>
                <h2 class="text-3xl font-bold text-gray-800">JobLauncher 的工作流程</h2>
            </div>
            
            <p class="text-gray-700 mb-6">
                <code class="bg-gray-100 px-2 py-1 rounded">JobLauncher</code> 是启动批处理作业的入口，它负责启动一个作业并处理作业的执行状态。在执行作业时，<code class="bg-gray-100 px-2 py-1 rounded">JobLauncher</code> 会创建 <code class="bg-gray-100 px-2 py-1 rounded">JobExecution</code> 对象，并通过 <code class="bg-gray-100 px-2 py-1 rounded">Job</code> 来启动作业。
            </p>
            
            <div class="code-block mb-8">
                <div class="copy-btn" onclick="copyCode(this)"><i class="far fa-copy"></i></div>
                <pre><code>public interface JobLauncher {
    JobExecution run(Job job, JobParameters jobParameters) 
        throws JobExecutionException;
}

public class SimpleJobLauncher implements JobLauncher {
    private JobRepository jobRepository;

    @Override
    public JobExecution run(Job job, JobParameters jobParameters) throws JobExecutionException {
        // 1. 创建 JobExecution
        JobExecution jobExecution = createJobExecution(job, jobParameters);

        // 2. 执行作业
        job.execute(jobExecution);

        // 3. 保存作业执行状态
        jobRepository.update(jobExecution);
        return jobExecution;
    }
}</code></pre>
            </div>
            
            <div class="grid md:grid-cols-3 gap-6 mb-8">
                <div class="bg-white p-6 rounded-xl shadow-sm card-hover">
                    <div class="text-purple-600 text-2xl mb-3">
                        <i class="fas fa-plus-circle"></i>
                    </div>
                    <h3 class="font-semibold text-lg mb-2">创建 JobExecution</h3>
                    <p class="text-gray-600">在 <code class="bg-gray-100 px-1 py-0.5 rounded">run</code> 方法中，<code class="bg-gray-100 px-1 py-0.5 rounded">SimpleJobLauncher</code> 会创建一个 <code class="bg-gray-100 px-1 py-0.5 rounded">JobExecution</code> 实例，它包含了作业执行的状态信息。</p>
                </div>
                <div class="bg-white p-6 rounded-xl shadow-sm card-hover">
                    <div class="text-purple-600 text-2xl mb-3">
                        <i class="fas fa-play-circle"></i>
                    </div>
                    <h3 class="font-semibold text-lg mb-2">执行作业</h3>
                    <p class="text-gray-600">然后通过 <code class="bg-gray-100 px-1 py-0.5 rounded">job.execute()</code> 来启动作业。</p>
                </div>
                <div class="bg-white p-6 rounded-xl shadow-sm card-hover">
                    <div class="text-purple-600 text-2xl mb-3">
                        <i class="fas fa-save"></i>
                    </div>
                    <h3 class="font-semibold text-lg mb-2">保存状态</h3>
                    <p class="text-gray-600">最后，<code class="bg-gray-100 px-1 py-0.5 rounded">jobRepository.update()</code> 方法会保存作业执行的状态。</p>
                </div>
            </div>
        </section>

        <div class="section-divider"></div>

        <!-- 3. StepExecution 和事务管理 -->
        <section class="mb-16">
            <div class="flex items-center mb-8">
                <div class="bg-purple-600 text-white rounded-full w-10 h-10 flex items-center justify-center mr-4">
                    <span class="text-xl font-bold">3</span>
                </div>
                <h2 class="text-3xl font-bold text-gray-800">StepExecution 和事务管理</h2>
            </div>
            
            <p class="text-gray-700 mb-6">
                每个 <code class="bg-gray-100 px-2 py-1 rounded">Step</code> 在执行时，都会创建一个 <code class="bg-gray-100 px-2 py-1 rounded">StepExecution</code> 实例，它包含了该步骤的执行状态、步骤的开始和结束时间、处理的项目数等信息。Spring Batch 使用事务管理器来确保每个 <code class="bg-gray-100 px-2 py-1 rounded">Step</code> 的数据处理是原子的。
            </p>
            
            <div class="code-block mb-8">
                <div class="copy-btn" onclick="copyCode(this)"><i class="far fa-copy"></i></div>
                <pre><code>public class StepExecution {
    private Long id;
    private String stepName;
    private Date startTime;
    private Date endTime;
    private ExitStatus exitStatus;
    private int readCount;
    private int writeCount;

    public void setStartTime(Date startTime) {
        this.startTime = startTime;
    }

    public void setEndTime(Date endTime) {
        this.endTime = endTime;
    }

    public void setExitStatus(ExitStatus exitStatus) {
        this.exitStatus = exitStatus;
    }
}</code></pre>
            </div>
            
            <div class="bg-yellow-50 border-l-4 border-yellow-500 p-4">
                <div class="flex">
                    <div class="flex-shrink-0 text-yellow-500">
                        <i class="fas fa-lightbulb"></i>
                    </div>
                    <div class="ml-3">
                        <p class="text-yellow-700">
                            <code class="bg-yellow-100 px-1 py-0.5 rounded">StepExecution</code> 保存了该步骤执行的所有信息，如开始时间、结束时间、读写的记录数等。<br>
                            事务管理确保每个 <code class="bg-yellow-100 px-1 py-0.5 rounded">Step</code> 中的操作要么全部成功，要么全部回滚，从而保证数据的一致性和完整性。
                        </p>
                    </div>
                </div>
            </div>
        </section>

        <div class="section-divider"></div>

        <!-- 4. ItemReader、ItemProcessor 和 ItemWriter 的实现 -->
        <section class="mb-16">
            <div class="flex items-center mb-8">
                <div class="bg-purple-600 text-white rounded-full w-10 h-10 flex items-center justify-center mr-4">
                    <span class="text-xl font-bold">4</span>
                </div>
                <h2 class="text-3xl font-bold text-gray-800">ItemReader、ItemProcessor 和 ItemWriter 的实现</h2>
            </div>
            
            <p class="text-gray-700 mb-6">
                <code class="bg-gray-100 px-2 py-1 rounded">ItemReader</code>、<code class="bg-gray-100 px-2 py-1 rounded">ItemProcessor</code> 和 <code class="bg-gray-100 px-2 py-1 rounded">ItemWriter</code> 是 Spring Batch 中的三个核心接口，用于批处理数据的读取、处理和写入。它们是 <code class="bg-gray-100 px-2 py-1 rounded">Step</code> 的关键组成部分，控制着数据流的各个环节。
            </p>
            
            <div class="grid md:grid-cols-3 gap-6 mb-8">
                <!-- ItemReader -->
                <div class="bg-white p-6 rounded-xl shadow-md card-hover">
                    <div class="flex items-center mb-4">
                        <div class="bg-blue-100 text-blue-600 p-3 rounded-full mr-4">
                            <i class="fas fa-book-reader text-xl"></i>
                        </div>
                        <h3 class="font-bold text-xl">ItemReader</h3>
                    </div>
                    <p class="text-gray-600 mb-4">数据读取的接口，通常用于从数据库、文件或消息队列中读取数据。</p>
                    <div class="code-block">
                        <div class="copy-btn" onclick="copyCode(this)"><i class="far fa-copy"></i></div>
                        <pre><code>public interface ItemReader&lt;T&gt; {
    T read() throws Exception;
}</code></pre>
                    </div>
                    <p class="text-gray-500 text-sm mt-3"><i class="fas fa-info-circle text-blue-500 mr-1"></i> <code class="bg-gray-100 px-1 py-0.5 rounded">read()</code> 方法每次从数据源中读取一条记录，并返回。</p>
                </div>
                
                <!-- ItemProcessor -->
                <div class="bg-white p-6 rounded-xl shadow-md card-hover">
                    <div class="flex items-center mb-4">
                        <div class="bg-green-100 text-green-600 p-3 rounded-full mr-4">
                            <i class="fas fa-cogs text-xl"></i>
                        </div>
                        <h3 class="font-bold text-xl">ItemProcessor</h3>
                    </div>
                    <p class="text-gray-600 mb-4">用于处理从 <code class="bg-gray-100 px-1 py-0.5 rounded">ItemReader</code> 读取到的数据。它对数据进行转换或过滤。</p>
                    <div class="code-block">
                        <div class="copy-btn" onclick="copyCode(this)"><i class="far fa-copy"></i></div>
                        <pre><code>public interface ItemProcessor&lt;I, O&gt; {
    O process(I item) throws Exception;
}</code></pre>
                    </div>
                    <p class="text-gray-500 text-sm mt-3"><i class="fas fa-info-circle text-green-500 mr-1"></i> <code class="bg-gray-100 px-1 py-0.5 rounded">process()</code> 方法接收一个输入项，并返回处理后的结果。</p>
                </div>
                
                <!-- ItemWriter -->
                <div class="bg-white p-6 rounded-xl shadow-md card-hover">
                    <div class="flex items-center mb-4">
                        <div class="bg-purple-100 text-purple-600 p-3 rounded-full mr-4">
                            <i class="fas fa-pen-fancy text-xl"></i>
                        </div>
                        <h3 class="font-bold text-xl">ItemWriter</h3>
                    </div>
                    <p class="text-gray-600 mb-4">用于将处理后的数据写入到目标数据源中，如写入数据库、文件或消息队列等。</p>
                    <div class="code-block">
                        <div class="copy-btn" onclick="copyCode(this)"><i class="far fa-copy"></i></div>
                        <pre><code>public interface ItemWriter&lt;T&gt; {
    void write(List&lt;? extends T&gt; items) 
        throws Exception;
}</code></pre>
                    </div>
                    <p class="text-gray-500 text-sm mt-3"><i class="fas fa-info-circle text-purple-500 mr-1"></i> <code class="bg-gray-100 px-1 py-0.5 rounded">write()</code> 方法接收一个列表作为参数，并将这些数据写入目标数据源中。</p>
                </div>
            </div>
            
            <!-- Data Flow Diagram -->
            <div class="bg-white rounded-xl shadow-md p-6">
                <h3 class="text-xl font-semibold text-gray-800 mb-4 flex items-center">
                    <i class="fas fa-exchange-alt text-purple-600 mr-2"></i> 数据处理流程图
                </h3>
                <div class="mermaid">
                    graph LR
                        A[ItemReader] --> B[ItemProcessor]
                        B --> C[ItemWriter]
                </div>
            </div>
        </section>

        <div class="section-divider"></div>

        <!-- 5. JobExecutionListener 和 StepExecutionListener -->
        <section class="mb-16">
            <div class="flex items-center mb-8">
                <div class="bg-purple-600 text-white rounded-full w-10 h-10 flex items-center justify-center mr-4">
                    <span class="text-xl font-bold">5</span>
                </div>
                <h2 class="text-3xl font-bold text-gray-800">JobExecutionListener 和 StepExecutionListener</h2>
            </div>
            
            <p class="text-gray-700 mb-6">
                <code class="bg-gray-100 px-2 py-1 rounded">JobExecutionListener</code> 和 <code class="bg-gray-100 px-2 py-1 rounded">StepExecutionListener</code> 允许开发者在作业和步骤执行前后执行自定义逻辑。这些监听器可以用于记录日志、发送通知等操作。
            </p>
            
            <div class="grid md:grid-cols-2 gap-8">
                <!-- JobExecutionListener -->
                <div class="bg-white p-6 rounded-xl shadow-sm card-hover">
                    <h3 class="font-semibold text-xl mb-4 flex items-center">
                        <i class="fas fa-tasks text-blue-500 mr-2"></i> JobExecutionListener 实现
                    </h3>
                    <div class="code-block mb-4">
                        <div class="copy-btn" onclick="copyCode(this)"><i class="far fa-copy"></i></div>
                        <pre><code>public class JobExecutionListenerSupport 
    implements JobExecutionListener {

    @Override
    public void beforeJob(JobExecution jobExecution) {
        // 作业开始前的自定义操作
    }

    @Override
    public void afterJob(JobExecution jobExecution) {
        // 作业结束后的自定义操作
    }
}</code></pre>
                    </div>
                    <div class="flex space-x-4">
                        <div class="flex items-start">
                            <div class="bg-blue-100 text-blue-600 p-2 rounded-full mr-2">
                                <i class="fas fa-play text-sm"></i>
                            </div>
                            <div>
                                <p class="font-medium">beforeJob</p>
                                <p class="text-gray-500 text-sm">方法在作业执行前被调用</p>
                            </div>
                        </div>
                        <div class="flex items-start">
                            <div class="bg-blue-100 text-blue-600 p-2 rounded-full mr-2">
                                <i class="fas fa-stop text-sm"></i>
                            </div>
                            <div>
                                <p class="font-medium">afterJob</p>
                                <p class="text-gray-500 text-sm">方法在作业执行后被调用</p>
                            </div>
                        </div>
                    </div>
                </div>
                
                <!-- StepExecutionListener -->
                <div class="bg-white p-6 rounded-xl shadow-sm card-hover">
                    <h3 class="font-semibold text-xl mb-4 flex items-center">
                        <i class="fas fa-step-forward text-purple-500 mr-2"></i> StepExecutionListener 实现
                    </h3>
                    <div class="code-block mb-4">
                        <div class="copy-btn" onclick="copyCode(this)"><i class="far fa-copy"></i></div>
                        <pre><code>public class StepExecutionListenerSupport 
    implements StepExecutionListener {

    @Override
    public void beforeStep(StepExecution stepExecution) {
        // 步骤开始前的自定义操作
    }

    @Override
    public ExitStatus afterStep(StepExecution stepExecution) {
        // 步骤结束后的自定义操作
        return ExitStatus.COMPLETED;
    }
}</code></pre>
                    </div>
                    <div class="flex space-x-4">
                        <div class="flex items-start">
                            <div class="bg-purple-100 text-purple-600 p-2 rounded-full mr-2">
                                <i class="fas fa-play text-sm"></i>
                            </div>
                            <div>
                                <p class="font-medium">beforeStep</p>
                                <p class="text-gray-500 text-sm">方法在步骤执行前被调用</p>
                            </div>
                        </div>
                        <div class="flex items-start">
                            <div class="bg-purple-100 text-purple-600 p-2 rounded-full mr-2">
                                <i class="fas fa-stop text-sm"></i>
                            </div>
                            <div>
                                <p class="font-medium">afterStep</p>
                                <p class="text-gray-500 text-sm">方法在步骤执行后被调用</p>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </section>

        <div class="section-divider"></div>

        <!-- 6. Spring Batch 的调度与作业流控制 -->
        <section class="mb-16">
            <div class="flex items-center mb-8">
                <div class="bg-purple-600 text-white rounded-full w-10 h-10 flex items-center justify-center mr-4">
                    <span class="text-xl font-bold">6</span>
                </div>
                <h2 class="text-3xl font-bold text-gray-800">Spring Batch 的调度与作业流控制</h2>
            </div>
            
            <p class="text-gray-700 mb-6">
                Spring Batch 提供了作业流控制的机制，可以通过分支和循环控制作业执行的顺序。例如，可以根据步骤的执行状态决定是否执行下一个步骤。
            </p>
            
            <h3 class="text-xl font-semibold text-gray-800 mt-8 mb-4 flex items-center">
                <i class="fas fa-random text-purple-600 mr-2"></i> Job Flow 控制
            </h3>
            
            <p class="text-gray-700 mb-6">
                Spring Batch 通过 <code class="bg-gray-100 px-2 py-1 rounded">FlowJob</code> 和 <code class="bg-gray-100 px-2 py-1 rounded">FlowStep</code> 来实现作业流控制，允许开发者通过条件判断来决定作业执行的路径。
            </p>
            
            <div class="code-block mb-8">
                <div class="copy-btn" onclick="copyCode(this)"><i class="far fa-copy"></i></div>
                <pre><code>public class FlowJob implements Job {
    private List&lt;Step&gt; steps;

    @Override
    public JobExecution run(JobParameters jobParameters) throws JobExecutionException {
        // 通过 Flow 控制作业的执行流
        for (Step step : steps) {
            StepExecution stepExecution = step.execute(jobExecution);
            if (stepExecution.getExitStatus().equals(ExitStatus.FAILED)) {
                // 如果某步失败，则跳出并标记作业失败
                break;
            }
        }
        return jobExecution;
    }
}</code></pre>
            </div>
            
            <div class="bg-gray-100 p-6 rounded-xl">
                <p class="text-gray-700">
                    <i class="fas fa-chevron-right text-purple-600 mr-2"></i> 在 <code class="bg-gray-200 px-1 py-0.5 rounded">FlowJob</code> 中，作业的执行顺序由 <code class="bg-gray-200 px-1 py-0.5 rounded">steps</code> 列表控制。如果某个 <code class="bg-gray-200 px-1 py-0.5 rounded">Step</code> 执行失败，作业将中止。
                </p>
            </div>
        </section>
    </div>

    <!-- Footer -->
    <footer class="bg-gray-900 text-gray-300 py-12">
        <div class="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
            <div class="flex flex-col items-center">
                <div class="text-xl font-semibold text-white mb-2">技术小馆</div>
                <a href="http://www.yuque.com/jtostring" class="text-blue-400 hover:text-blue-300 transition duration-200">
                    <i class="fas fa-external-link-alt mr-1"></i> http://www.yuque.com/jtostring
                </a>
            </div>
        </div>
    </footer>

    <script>
        // Initialize Mermaid
        mermaid.initialize({
            startOnLoad: true,
            theme: 'default',
            flowchart: {
                useMaxWidth: true,
                htmlLabels: true
            }
        });
        
        // Copy code button functionality
        function copyCode(button) {
            const codeBlock = button.parentElement;
            const code = codeBlock.querySelector('code').textContent;
            navigator.clipboard.writeText(code).then(() => {
                const originalIcon = button.innerHTML;
                button.innerHTML = '<i class="fas fa-check"></i>';
                setTimeout(() => {
                    button.innerHTML = originalIcon;
                }, 2000);
            });
        }
        
        // Add smooth scrolling to all links
        document.querySelectorAll('a[href^="#"]').forEach(anchor => {
            anchor.addEventListener('click', function (e) {
                e.preventDefault();
                document.querySelector(this.getAttribute('href')).scrollIntoView({
                    behavior: 'smooth'
                });
            });
        });
    </script>
</body>
</html>